#ifndef __HTTP_H
#define __HTTP_H

#include <sys/types.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <string.h>
#include <sys/time.h>

#define lstrcmpi strcasecmp

#define SOCKET		int
#define INVALID_SOCKET	-1
#define closesocket	close

#ifndef SSL_MAX_PASSWD_SIZE
#define SSL_MAX_PASSWD_SIZE	255
#endif

#ifndef SOCKET_BUFFER_SIZE
#define SOCKET_BUFFER_SIZE      1024
#endif


#define SSL2	SSLv2_client_method()
#define SSL3	SSLv3_client_method()



#define HTTP_ERR_SUCCESS        0
#define HTTP_ERR_ARGS           -1
#define HTTP_ERR_WRITE          -2
#define HTTP_ERR_READ           -3
#define HTTP_ERR_FORMAT         -4
#define HTTP_ERR_OUTOFMEM	-5

struct tagHTTPHDR
{
    char* name;
    int nname;
    char* value;
    int nvalue;
    tagHTTPHDR* next;
};
typedef tagHTTPHDR HTTPHDR,*LPHTTPHDR;

struct tagHTTPANSWER
{
    int result;
    char* content;
    int length;
    LPHTTPHDR header;
};
typedef tagHTTPANSWER HTTPANSWER,*LPHTTPANSWER;


class SSLCtx
{
private:
	SSL_CTX* ctx;
	char passwd[SSL_MAX_PASSWD_SIZE];

	static int pem_passwd_cb(char* buf,int size,int rwflag,void*);
public:
	SSLCtx(void);
	~SSLCtx(void);
	int create(SSL_METHOD* method);
	int destroy(void);
	int set_cipher(const char* cipher);
	SSL_CTX* get_context(void);
	int set_certificate(const char* certfile,const char* keyfile,const char* pass);

	static int initialize(void);
};


class Socket
{
private:
    SOCKET fd;
    SSL* ssl;
    SSLCtx* ssl_ctx;
// timeouts
    int ctimeout;
    int rtimeout;
    int wtimeout;
// ssl flag
    int secure;
    
// input cache
    char inbuf[SOCKET_BUFFER_SIZE];
    int inoffset;
    int insize;
// output cache
    char outbuf[SOCKET_BUFFER_SIZE];
    int outsize;
		    

    int connect(const char* host);
    int sslconnect(void);
    int disconnect(void);

    int sslwrite(const char* buf,int size);
    int sslread(char* buf,int size);
    int fdwrite(const char* buf,int size);
    int fdread(char* buf,int size);

    int directwrite(const char* buf,int size);
    int directread(char* buf,int size);
public:
    Socket(void);
    ~Socket(void);
    void attach(SSLCtx* ctx);
    void set_timeouts(int c,int r,int w);// set connect, read and write timeouts
    int open(const char* host,int sec);	 // connect to server
    int set_secure(void);		 // enable secure


    void reset(void);                    // reset input and output buffers
    int flush(void);                     // flush output buffer
	
    int _getchar(void);                   // read char from input buffer
    int read(char* dst,int len);         // read from input buffer
    int readln(char* dst,int len);       // read line from input buffer
    int _putchar(int ch);                 // write char to output buffer
    int write(const char* src,int len);  // write to output buffer
    int dwrite(const char* src,int len); // direct write to output
    int writeln(const char* src,int len);// write line to output buffer
    int printf(const char* fmt,...);     // formated print to output buffer
    int vprintf(const char* fmt,va_list ap);     // formated print to output buffer
				    
    int close(void);			 // flush and close connection

private:
    static char* get_next_part(char* buf,char delimiter);
public:
    static char* trim_buf(char* buf,int size);
   
    int http_send_request(LPHTTPANSWER result,const char* method,const char* resource,const char* contenttype,const char* content,int length,
        const char* useragent,const char* host,int keepalive,const char* proxyauthtype,const char* proxyauth,int waitcontent);
    int http_free_answer(LPHTTPANSWER result);
};


#endif
